#include "st7026.h"
#include "stm32f1xx_hal.h"
#include "bsp.h"
#include <math.h>

uint8_t i;

#define SPI_DELAY 1

void delay(uint32_t count) {
	for(uint32_t i = 0; i < count; i++) {
		i = i;
	}
}


void write_data(unsigned char byte)
{
	SPI1_SCK_GPIO_Port->BSRR = (uint32_t) SPI1_SCK_Pin;
	SPI1_NSS_GPIO_Port->BRR = (uint32_t) SPI1_NSS_Pin;
	delay(SPI_DELAY);
	
    SPI1_MOSI_GPIO_Port->BSRR = (uint32_t) SPI1_MOSI_Pin;
    SPI1_SCK_GPIO_Port->BRR = (uint32_t) SPI1_SCK_Pin;
	delay(SPI_DELAY);
    SPI1_SCK_GPIO_Port->BSRR = (uint32_t) SPI1_SCK_Pin;
    delay(SPI_DELAY);
	
	for(i=0;i<8;i++)
	{
		(byte&0x80) ? (SPI1_MOSI_GPIO_Port->BSRR = (uint32_t) SPI1_MOSI_Pin) : (SPI1_MOSI_GPIO_Port->BRR = (uint32_t) SPI1_MOSI_Pin);
		byte <<= 1;
		SPI1_SCK_GPIO_Port->BRR = (uint32_t) SPI1_SCK_Pin;
		delay(SPI_DELAY);
		
		SPI1_SCK_GPIO_Port->BSRR = (uint32_t) SPI1_SCK_Pin;
		delay(SPI_DELAY);
	}
	SPI1_NSS_GPIO_Port->BSRR = (uint32_t) SPI1_NSS_Pin;
	delay(SPI_DELAY);
}

void write_com(unsigned char byte)
{
	SPI1_SCK_GPIO_Port->BSRR = (uint32_t) SPI1_SCK_Pin;
	SPI1_NSS_GPIO_Port->BRR = (uint32_t) SPI1_NSS_Pin;
	delay(SPI_DELAY);
	
    SPI1_MOSI_GPIO_Port->BRR = (uint32_t) SPI1_MOSI_Pin;
	SPI1_SCK_GPIO_Port->BRR = (uint32_t) SPI1_SCK_Pin;
	delay(SPI_DELAY);
    SPI1_SCK_GPIO_Port->BSRR = (uint32_t) SPI1_SCK_Pin;
	delay(SPI_DELAY);
    
	for(i=0;i<8;i++)
	{
		(byte&0x80) ? (SPI1_MOSI_GPIO_Port->BSRR = (uint32_t) SPI1_MOSI_Pin) : (SPI1_MOSI_GPIO_Port->BRR = (uint32_t) SPI1_MOSI_Pin);
		byte <<= 1;
		SPI1_SCK_GPIO_Port->BRR = (uint32_t) SPI1_SCK_Pin;
		delay(SPI_DELAY);
		
		SPI1_SCK_GPIO_Port->BSRR = (uint32_t) SPI1_SCK_Pin;
		delay(SPI_DELAY);
	}
	SPI1_NSS_GPIO_Port->BSRR = (uint32_t) SPI1_NSS_Pin;
	delay(SPI_DELAY);
}



void st7026_drawByte(uint8_t columnPage, uint8_t row, uint8_t byteData) {
	if(columnPage > 5 || row > 3) {
		return;
	}
	
	write_com(0x2a);
	write_data(columnPage + 3);
	write_data(columnPage + 3);
	
	write_com(0x2b);
	write_data(row);
	write_data(row);
	
	write_com(0x0f);
	write_data(1 - 1);
	
	write_com(0x2c);
	write_data(byteData);
}


unsigned char buffer[6][4];

void bufferInit(unsigned char byteData) {
	for(uint8_t c = 0; c < 6; c++) {
		for(uint8_t r = 0; r < 4; r++) {
			buffer[c][r] = byteData;
		}
	}
}
void st7026_fillByte(uint8_t byteData) {
	write_com(0x2a);
	write_data(0 + 3);
	write_data(5 + 3);
	
	write_com(0x2b);
	write_data(0);
	write_data(3);
	
	write_com(0x0f);
	write_data(6 * 4 - 1);
	
	write_com(0x2c);
		
	for(uint8_t i = 0; i < 24; i++) {
		write_data(byteData);
	}
	
	bufferInit(byteData);
}

void st7026_drawPiexl(uint8_t seg, uint8_t com, uint8_t color) {
	uint8_t column = seg/8;
	uint8_t temp = buffer[column][com];
	
	if(color) {
		temp |= (1<<(seg%8));
	} else {
		temp &= ~(1<<(seg%8));
	}
	
	buffer[column][com] = temp;
	
	//write_com(0x2C);
	st7026_drawByte(column, com, temp);
}




unsigned long vopGrade;

void _st7026_setVopGrade(unsigned long vg) {
	write_com(0xC0); // set Vop
    write_data((unsigned char)vg); // set Vop 6V
    write_data((unsigned char)(vg >> 8));
}
void st7026_setVop(float vop) {
	
	vopGrade = ceil( (vop-4.0)/0.04);
	_st7026_setVopGrade(vopGrade);
}

void st7026_vopAdd(void) {
	if(vopGrade < 0x1ff) {
		++vopGrade;
		_st7026_setVopGrade(vopGrade);
	}
}

void st7026_vopDec(void) {
	if(vopGrade > 0) {
		--vopGrade;
		_st7026_setVopGrade(vopGrade);
	}
}

void st7026_init(void) {

    write_com(0x01); // sreset
	write_com(0x11); // sleep out
    write_com(0xB7); // LCD Scan set
    write_data(0x00); // MX=0
	
	st7026_setVop(5.0);
	
    write_com(0xC3); // set Bias
    write_data(0x01); // set 1/3 Bias
    //write_com(0xB3); // set LED waveform
    //write_data(0xFF); // set LED width 0xFF
	
    write_com(0x2A); // set SEG address
    write_data(0x03); // set Start at SEG0
    write_data(0x0B); // set End at SEG47
    write_com(0x2B); // set COM address
    write_data(0x00); // set Start at COM0
    write_data(0x03); // set Start at COM3
	
    write_com(0xB2); // set fFR
    write_data(0x13); // set fFR=80Hz
	
    write_com(0xD2); // set power control
    write_data(0x06); // OSC & Booster on
    HAL_Delay(20); // delay 20ms
    write_com(0xD2); // set power control
    write_data(0x04); // V0 on
    HAL_Delay(20); // delay 20ms
    write_com(0xD2); // set power control
    write_data(0x00); // FOL on
    HAL_Delay(20); // delay 20ms
	
    write_com(0x0F); // set data length
    //(3-SPI only)
    write_data(0x6B); // full range
    
    //(black)
    write_com(0x29); // Display o
	
	
}


